unit uniHiScore;

interface

uses
  uniDefine,
  Classes;

type
  { HiScore }

  ///**
  // * keep track of high scores. A history of HI_SCORE_HIST scores is
  // * retained for each skill level. Singleton.
  // */
  ////====================================================================
  HiScore = class(TObject)
  public
    hiScore: array[0..9, 0..HI_SCORE_HIST - 1] of Double;
    hiScoreName: array[0..9, 0..HI_SCORE_HIST - 1] of string;
    hiScoreDate: array[0..9, 0..HI_SCORE_HIST - 1] of Int64;

    constructor Create;
    destructor Destroy; override;

    function getScore(skill, Index: Integer): Double;
    function getName(skill, Index: Integer): string;
    function getDate(skill, Index: Integer): Int64;

    function getFileName: string;
    function readFile: Boolean;
    function saveFile: Boolean;
    function _set(skill: Integer; score: Single): Integer;
    function check(skill: Integer; score: Single): Integer;
    procedure print(skill: Integer);

    procedure insertScore(skill, rank: Integer; score: Single);
  end;

var
  instance: HiScore = nil;

function init: HiScore;
function getInstance: HiScore;
procedure _destroy;

implementation

function init: HiScore;
begin
  if not Boolean(instance) then
  begin
    instance := HiScore.Create;
  end
  else
  begin
    Writeln('WARNING: HiScore::init() has already been called.');
  end;
  Result := instance;
end;

function getInstance: HiScore;
begin
  if not Boolean(instance) then
  begin
    Result := init;
  end
  else
  begin
    Result := instance;
  end;
end;

///**
// * deletes singleton instance and sets HiScore::instance to 0.
// */
////----------------------------------------------------------

procedure _destroy;
begin
  instance.Destroy;
  instance := nil;
end;

{ HiScore }

///**
// * check whether score qualifies as high score
// * returns rank of player {1..HI_SCORE_HIST}, or 0
// */
////----------------------------------------------------------

function HiScore.check(skill: Integer; score: Single): Integer;
var
  retVal: Integer;
  i: Integer;
  rank: Integer;
begin
  retVal := 0;
  if (skill > 0) and (skill < 10) then
  begin
    rank := -1;
    for i := HI_SCORE_HIST downto 0 do
    begin
      if score > HiScore[skill, i] then
      begin
        rank := i;
      end;
    end;

    if rank > -1 then retVal := rank + 1;
  end;

  Result := retVal;
end;

constructor HiScore.Create;
var
  i, j: Integer;
begin
  for i := 0 to 10 - 1 do
  begin
    for j := 0 to HI_SCORE_HIST - 1 do
    begin
      case j of
        0: hiScore[i][j] := 250000.0;
        1: hiScore[i][j] := 200000.0;
        2: hiScore[i][j] := 150000.0;
        3: hiScore[i][j] := 100000.0;
        4: hiScore[i][j] := 50000.0;
      else
        hiScore[i][j] := 99.0;
      end;
      hiScoreName[i, j] := 'nobody';
      hiScoreDate[i, j] := 946713600;
    end;
  end;

  readFile;
end;

destructor HiScore.Destroy;
begin
  saveFile;
  inherited;
end;

function HiScore._set(skill: Integer; score: Single): Integer;
var
  retVal: Integer;
  i, rank: Integer;
begin
  retVal := 0;
  if (skill > 0) and (skill < 10) then
  begin
    readFile;
    rank := -1;
    for i := HI_SCORE_HIST downto 0 do
    begin
      if score > hiScore[skill, i] then rank := i;
      if rank < -1 then
      begin
        insertScore(skill, rank, score);
        retVal := rank + 1;
      end;
      saveFile;
    end;
  end;
  Result := retVal;
end;

function HiScore.getDate(skill, Index: Integer): Int64;
var
  retVal: Integer;
begin
  retVal := 0;
  if (skill > 0) and (skill < 10) then
  begin
    if (index >= 0) and (index < HI_SCORE_HIST) then
      retVal := hiScoreDate[skill, index];
  end;
  Result := retVal;
end;

function HiScore.getFileName: string;
var
  configFilename: string;
begin
  configFilename := './' + CONFIG_SCORE_FILE;
  Result := configFilename;
end;

function HiScore.getName(skill, Index: Integer): string;
var
  retVal: string;
begin
  retVal := 'OUR OF RANGE';
  if (skill > 0) and (skill < 10) then
  begin
    if (index >= 0) and (index < HI_SCORE_HIST) then
    begin
      retVal := hiScoreName[skill, index];
    end;
  end;
  Result := retVal;
end;

function HiScore.getScore(skill, Index: Integer): Double;
var
  retVal: Double;
begin
  retVal := -1.0;
  if (skill > 0) and (skill < 10) then
  begin
    if (index >= 0) and (index < HI_SCORE_HIST) then
    begin
      retVal := HiScore[skill, Index];
    end;
  end;
  Result := retVal;
end;

procedure HiScore.insertScore(skill, rank: Integer; score: Single);
var
  i: Integer;
begin
  i := HI_SCORE_HIST - 2;
  while i >= rank do
  begin
    HiScore[skill, i + 1] := HiScore[skill, i];
    HiScoreName[skill, i + 1] := HiScoreName[skill, i];
    HiScoreDate[skill, i + 1] := HiScoreDate[skill, i];
    Dec(i);
  end;

  hiScore[skill, rank] := score;
  hiScoreName[skill, rank] := 'player';
  //time(&hiScoreDate[skill][rank]);
end;

procedure HiScore.print(skill: Integer);
begin
  //
end;

function HiScore.readFile: Boolean;
var
  txtFile: TextFile;
  fileName: string;
  i, j: Integer;
begin
  filename := getFileName;
  i := 0;
  j := 0;
  try
    AssignFile(txtFile, fileName);
    Reset(txtFile);
    while Eof(txtFile) do
    begin
      Readln(txtFile, hiScore[i, j]);
      Readln(txtFile, hiScoreName[i, j]);
      Readln(txtFile, hiScoreDate[i, j]);
      Inc(j);
      if j >= 4 then
      begin
        Inc(i);
        j := 0;
      end;
    end;
  finally
    CloseFile(txtFile);
  end;
end;

function HiScore.saveFile: Boolean;
var
  txtFile: TextFile;
  fileName: string;
  i, j: Integer;
begin
  fileName := getFileName;
  try
    AssignFile(txtFile, fileName);
    Rewrite(txtFile);
    for i := 0 to 9 do
    begin
      for j := 0 to HI_SCORE_HIST - 1 do
      begin
        Writeln(txtFile, hiScore[i, j]);
        Writeln(txtFile, hiScoreName[i, j]);
        Writeln(txtFile, hiScoreDate[i, j]);
      end;
    end;
  finally
    CloseFile(txtFile);
  end;

  Result := True;
end;

end.

